package com.alpha.eceasy.mall.util;

import lombok.experimental.UtilityClass;

import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;

/**
 * 流过滤工具
 *
 * @author huangpengfei
 * @since 2024-03-21
 */
@UtilityClass
public class StreamFilters {
    /**
     * 通过对象属性值去重（多对象，依顺序过滤）
     */
    @SafeVarargs
    public <T> Predicate<T> distinctByKey(Function<? super T, ?>... keyExtractor) {
        ConcurrentHashMap<Object, Boolean> seem = new ConcurrentHashMap<>();
        return item -> {
            Object key = null;
            for (Function<? super T, ?> function : keyExtractor) {
                key = function.apply(item);
                if (Objects.nonNull(key)) {
                    break;
                }
            }
            Objects.requireNonNull(key, "key must contain be not null");
            return seem.putIfAbsent(key, Boolean.TRUE) == null;
        };
    }

    /**
     * 通过对象属性值去重（含null）
     */
    public <T> Predicate<T> distinctByKeyContainNull(Function<? super T, ?> keyExtractor) {
        ConcurrentHashMap<Object, Boolean> seem = new ConcurrentHashMap<>();
        return item -> Optional.ofNullable(keyExtractor.apply(item))
                .map(key -> seem.putIfAbsent(key, Boolean.TRUE) == null)
                .orElseGet(() -> seem.putIfAbsent("null", Boolean.TRUE) == null);
    }

    /**
     * 通过对象属性值去重（去除null）
     */
    public <T> Predicate<T> distinctByKeyNonNull(Function<? super T, ?> keyExtractor) {
        ConcurrentHashMap<Object, Boolean> seem = new ConcurrentHashMap<>();
        return item -> Optional.ofNullable(keyExtractor.apply(item))
                .map(key -> seem.putIfAbsent(key, Boolean.TRUE) == null)
                .orElse(false);
    }
}
